/**
  ******************************************************************************
  * @文件     lcd.c
  * @作者     hero_cao
  * @版本     V1.0.0
  * @日期     2020/08/14
  * @概要     tftlcd驱动
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "./board/bsp.h"
#include "./lcd/lcd.h"
#include "./lcd/lcdfont.h"
#include "./spi/spi.h"

/* Exported types ----------------------------------------------------------- */
uint32_t g_point_color = 0xF800;    /* 画笔颜色 */
uint32_t g_back_color  = 0xFFFF;    /* 背景色 */
_lcd_dev lcddev;


/**
  * @brief  写寄存器函数
  * @param  regval-寄存器值
  * @retval 无
  */
static void lcd_wr_reg(uint8_t regval)
{   
#ifdef USE_XMC_LCD
	LCD->LCD_REG = regval & 0xff;
#else
	gpio_bits_reset(GPIOE, GPIO_PINS_13);
	spi4_write_byte(regval & 0xff);
	gpio_bits_set(GPIOE, GPIO_PINS_13);
#endif
}

/**
  * @brief  写LCD数据
  * @param  data-要写入的值
  * @retval 无
  */
static void lcd_wr_data(uint8_t data)
{
#ifdef USE_XMC_LCD	
	LCD->LCD_RAM = data & 0xff;
#else
	spi4_write_byte(data & 0xff);
#endif	
}

/**
  * @brief  ili9341初始化指令
  * @param  无
  * @retval 无
  */
static void ili9341_16bit_init(void)
{	
	lcd_wr_reg(0xcf);  
	lcd_wr_data(0x00); 
	lcd_wr_data(0xc1); 
	lcd_wr_data(0x30);
	
	lcd_wr_reg(0xed);  
	lcd_wr_data(0x64); 
	lcd_wr_data(0x03); 
	lcd_wr_data(0x12); 
	lcd_wr_data(0x81); 
	
	lcd_wr_reg(0xe8);  
	lcd_wr_data(0x85); 
	lcd_wr_data(0x10); 
	lcd_wr_data(0x7a); 
	
	lcd_wr_reg(0xcb);  
	lcd_wr_data(0x39); 
	lcd_wr_data(0x2c); 
	lcd_wr_data(0x00); 
	lcd_wr_data(0x34); 
	lcd_wr_data(0x02); 
	
	lcd_wr_reg(0xf7);  
	lcd_wr_data(0x20); 
	
	lcd_wr_reg(0xea);  
	lcd_wr_data(0x00); 
	lcd_wr_data(0x00); 
	
	lcd_wr_reg(0xc0);    //Power control 
	lcd_wr_data(0x1b);   //VRH[5:0] 
	
	lcd_wr_reg(0xc1);    //Power control 
	lcd_wr_data(0x01);   //SAP[2:0];BT[3:0] 
	
	lcd_wr_reg(0xc5);    //VCM control 
	lcd_wr_data(0x30); 	 //3F
	lcd_wr_data(0x30); 	 //3C
	
	lcd_wr_reg(0xc7);    //VCM control2 
	lcd_wr_data(0xb7); 
	
	lcd_wr_reg(0x36);    // Memory Access Control 
	lcd_wr_data(0x48); 
	
	lcd_wr_reg(0x3a);   
	lcd_wr_data(0x55); 
	
	lcd_wr_reg(0xb1);   
	lcd_wr_data(0x00);   
	lcd_wr_data(0x1a); 
	
	lcd_wr_reg(0xb6);    // Display Function Control 
	lcd_wr_data(0x0a); 
	lcd_wr_data(0xa2); 
	
	lcd_wr_reg(0xf2);    // 3Gamma Function Disable 
	lcd_wr_data(0x00); 
	
	lcd_wr_reg(0x26);    //Gamma curve selected 
	lcd_wr_data(0x01); 
	
	lcd_wr_reg(0xe0);    //Set Gamma 
	lcd_wr_data(0x0f); 
	lcd_wr_data(0x2a); 
	lcd_wr_data(0x28); 
	lcd_wr_data(0x08); 
	lcd_wr_data(0x0e); 
	lcd_wr_data(0x08); 
	lcd_wr_data(0x54); 
	lcd_wr_data(0xa9); 
	lcd_wr_data(0x43); 
	lcd_wr_data(0x0a); 
	lcd_wr_data(0x0f); 
	lcd_wr_data(0x00); 
	lcd_wr_data(0x00); 
	lcd_wr_data(0x00); 
	lcd_wr_data(0x00); 
	
	lcd_wr_reg(0xe1);    //Set Gamma 
	lcd_wr_data(0x00); 
	lcd_wr_data(0x15); 
	lcd_wr_data(0x17); 
	lcd_wr_data(0x07); 
	lcd_wr_data(0x11); 
	lcd_wr_data(0x06); 
	lcd_wr_data(0x2b); 
	lcd_wr_data(0x56); 
	lcd_wr_data(0x3c); 
	lcd_wr_data(0x05); 
	lcd_wr_data(0x10); 
	lcd_wr_data(0x0f); 
	lcd_wr_data(0x3f); 
	lcd_wr_data(0x3f); 
	lcd_wr_data(0x0f); 
	
	lcd_wr_reg(0x2b); 
	lcd_wr_data(0x00);
	lcd_wr_data(0x00);
	lcd_wr_data(0x01);
	lcd_wr_data(0x3f);
	
	lcd_wr_reg(0x2a); 
	lcd_wr_data(0x00);
	lcd_wr_data(0x00);
	lcd_wr_data(0x00);
	lcd_wr_data(0xef);
	
	lcd_wr_reg(0x11);	//Exit Sleep
}

/**
  * @brief  gc9307初始化指令
  * @param  无
  * @retval 无
  */
static void gc9307_8bit_init(void)
{	  
	lcd_wr_reg(0x11);	//sleep out

    // gc9307 gamma setting
    lcd_wr_reg(0xf0);
    lcd_wr_data(0x02);
    lcd_wr_data(0x01);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_data(0x02);
    lcd_wr_data(0x09);

    lcd_wr_reg(0xf1);
    lcd_wr_data(0x01);
    lcd_wr_data(0x02);
    lcd_wr_data(0x00);
    lcd_wr_data(0x11);
    lcd_wr_data(0x1c);
    lcd_wr_data(0x15);

    lcd_wr_reg(0xf2);
    lcd_wr_data(0x0a);
    lcd_wr_data(0x07);
    lcd_wr_data(0x29);
    lcd_wr_data(0x04);
    lcd_wr_data(0x04);
    lcd_wr_data(0x38);

    lcd_wr_reg(0xf3);
    lcd_wr_data(0x15);
    lcd_wr_data(0x0d);
    lcd_wr_data(0x55);
    lcd_wr_data(0x04);
    lcd_wr_data(0x03);
    lcd_wr_data(0x65);

    lcd_wr_reg(0x35);  //TE on
    lcd_wr_data(0x00);

    lcd_wr_reg(0x3a);  //Interface pixel format
    lcd_wr_data(0x05); //65K
}

/**
  * @brief  st7789初始化指令
  * @param  无
  * @retval 无
  */
static void st7789_spi_init(void)
{	
	lcd_wr_reg(0x11);  //sleep out   
	Delay_ms(100);
	
	// ST7789S Frame rate setting
    lcd_wr_reg(0xb2);
    lcd_wr_data(0x5a);
    lcd_wr_data(0x7f);
    lcd_wr_data(0x01);
    lcd_wr_data(0x33);
    lcd_wr_data(0x33);

    // Gate Control
    lcd_wr_reg(0xb7);
    lcd_wr_data(0x56);
    
    lcd_wr_reg(0xb8);
    lcd_wr_data(0x56);

    // ST7789S Power setting
    lcd_wr_reg(0xbb);
    lcd_wr_data(0x18);

    lcd_wr_reg(0xc0);
    lcd_wr_data(0x2c);

    lcd_wr_reg(0xc2);
    lcd_wr_data(0x01);

    lcd_wr_reg(0xc3);
    lcd_wr_data(0x1f);

    lcd_wr_reg(0xc4);
    lcd_wr_data(0x20);

    lcd_wr_reg(0xc6);
    lcd_wr_data(0x0f);

    lcd_wr_reg(0xd0);
    lcd_wr_data(0xa6);
    lcd_wr_data(0xa1);

    // ST7789S gamma setting
    lcd_wr_reg(0xe0);
    lcd_wr_data(0x70);
    lcd_wr_data(0x00);
    lcd_wr_data(0x06);
    lcd_wr_data(0x09);
    lcd_wr_data(0x0b);
    lcd_wr_data(0x2a);
    lcd_wr_data(0x3c);
    lcd_wr_data(0x33);
    lcd_wr_data(0x4b);
    lcd_wr_data(0x08);
    lcd_wr_data(0x16);
    lcd_wr_data(0x14);
    lcd_wr_data(0x2a);
    lcd_wr_data(0x23);

    lcd_wr_reg(0xe1);
    lcd_wr_data(0xd0);
    lcd_wr_data(0x00);
    lcd_wr_data(0x06);
    lcd_wr_data(0x09);
    lcd_wr_data(0x0b);
    lcd_wr_data(0x29);
    lcd_wr_data(0x36);
    lcd_wr_data(0x54);
    lcd_wr_data(0x4b);
    lcd_wr_data(0x0d);
    lcd_wr_data(0x16);
    lcd_wr_data(0x14);
    lcd_wr_data(0x28);
    lcd_wr_data(0x22);

    lcd_wr_reg(0x35);  //Memory data access control
    lcd_wr_data(0x00);  //TE

    lcd_wr_reg(0x3A);  //Interface pixel format
    lcd_wr_data(0x55);  //65K
    
    lcd_wr_reg(0x21);  //ips Display inversion on
}

/**
  * @brief  写寄存器函数
  * @param  regno-寄存器地址
  * @param  data-要写入的数据
  * @retval 无
  */
static void lcd_write_reg(volatile uint16_t regno, volatile uint16_t data)
{	
	lcd_wr_reg(regno);
	lcd_wr_data(data);  		 
}

/**
 * @brief       LCD读数据
 * @param       无
 * @retval      读取到的数据
 */
static uint16_t lcd_rd_data(void)
{
	volatile uint16_t ram;  /* 防止被优化 */
#ifdef USE_XMC_LCD
#if DATA_BIT==16
	ram = LCD->LCD_RAM;
#else
	ram = (uint8_t)(LCD->LCD_RAM);
	ram <<= 8;
	ram = (uint8_t)(LCD->LCD_RAM);
#endif	
#endif	
	
	return ram;
}

/**
  * @brief  LCD开启显示
  * @param  无
  * @retval 无
  */
static void lcd_display_on(void)
{					   
	lcd_wr_reg(0x29);
}

/**
  * @brief  LCD写颜色
  * @param  rgb_code-16位颜色值
  * @retval 无
  */
void lcd_write_color(uint16_t rgb_code)
{
#if DATA_BIT==16
	LCD->LCD_RAM = rgb_code;
#else
	lcd_wr_data(rgb_code >> 8);
	lcd_wr_data(rgb_code & 0xff);
#endif
}

/**
  * @brief  准备写GRAM
  * @param  无
  * @retval 无
  */
void lcd_write_ram_prepare(void)
{
 	lcd_wr_reg(lcddev.wramcmd);	  
}

/**
  * @brief  设置光标位置
  * @param  x,y-坐标
  * @retval 无
  */
void lcd_set_cursor(uint16_t x, uint16_t y, uint16_t dx, uint16_t dy)
{	 	
	lcd_wr_reg(lcddev.setxcmd);
	lcd_wr_data(x >> 8);
	lcd_wr_data(x & 0xff);
#if DATA_BIT==8
	lcd_wr_data((x + dx) >> 8);
	lcd_wr_data((x + dx) & 0xff);
#endif
	lcd_wr_reg(lcddev.setycmd);
	lcd_wr_data(y >> 8);
	lcd_wr_data(y & 0xff);
#if DATA_BIT==8
	lcd_wr_data((y + dy) >> 8);
	lcd_wr_data((y + dy) & 0xff);
#endif
} 

/**
  * @brief  设置LCD的自动扫描方向
  * @param  dir-0~7,代表8个方向(具体定义见lcd.h)
  * @retval 无
  */  	   
void lcd_scan_dir(uint8_t dir)
{	
	uint16_t regval = 0;
	uint16_t dirreg = 0;
	uint16_t temp;

	if(lcddev.dir==1) {		   
		switch(dir) {
			case 0:dir=6;break;
			case 1:dir=7;break;
			case 2:dir=4;break;
			case 3:dir=5;break;
			case 4:dir=1;break;
			case 5:dir=0;break;
			case 6:dir=3;break;
			case 7:dir=2;break;	     
		}
	}
	switch(dir) {
		case L2R_U2D://从左到右,从上到下
			regval|=(0<<7)|(0<<6)|(0<<5); 
			break;
		case L2R_D2U://从左到右,从下到上
			regval|=(1<<7)|(0<<6)|(0<<5); 
			break;
		case R2L_U2D://从右到左,从上到下
			regval|=(0<<7)|(1<<6)|(0<<5); 
			break;
		case R2L_D2U://从右到左,从下到上
			regval|=(1<<7)|(1<<6)|(0<<5); 
			break;	 
		case U2D_L2R://从上到下,从左到右
			regval|=(0<<7)|(0<<6)|(1<<5); 
			break;
		case U2D_R2L://从上到下,从右到左
			regval|=(0<<7)|(1<<6)|(1<<5); 
			break;
		case D2U_L2R://从下到上,从左到右
			regval|=(1<<7)|(0<<6)|(1<<5); 
			break;
		case D2U_R2L://从下到上,从右到左
			regval|=(1<<7)|(1<<6)|(1<<5); 
			break;	 
	}
	dirreg = 0x36;
#ifdef USE_XMC_LCD
	regval |= 0x08;		/* 设置BGR位 */
#endif
	lcd_write_reg(dirreg,regval);
	if(regval & 0x20) {
		if(lcddev.width < lcddev.height) {
			temp = lcddev.width;
			lcddev.width = lcddev.height;
			lcddev.height = temp;
		}
	} else {
		if(lcddev.width > lcddev.height) {
			temp = lcddev.width;
			lcddev.width = lcddev.height;
			lcddev.height = temp;
		}
	}  
	
	lcd_wr_reg(lcddev.setxcmd); 
	lcd_wr_data(0);
	lcd_wr_data(0);
	lcd_wr_data((lcddev.width-1) >> 8);
	lcd_wr_data((lcddev.width-1) & 0xff);
	lcd_wr_reg(lcddev.setycmd); 
	lcd_wr_data(0);
	lcd_wr_data(0);
	lcd_wr_data((lcddev.height-1) >> 8);
	lcd_wr_data((lcddev.height-1) & 0xff);
}

/**
 * @brief       读取个某点的颜色值
 * @param       x,y:坐标
 * @retval      此点的颜色
 */
uint32_t lcd_read_point(uint16_t x, uint16_t y)
{
    uint16_t r = 0, g = 0, b = 0;

    if (x >= lcddev.width || y >= lcddev.height) return 0;  /* 超过了范围,直接返回 */

    lcd_set_cursor(x, y, 0, 0);       /* 设置坐标 */

    lcd_wr_reg(0x2e);			/* 9341/5310/1963/7789/7796/9806 等发送读GRAM指令 */

    r = lcd_rd_data();          /* 假读(dummy read) */

    r = lcd_rd_data();          /* 实际坐标颜色 */

    /* 9341/5310/5510/7789/9806 要分2次读出 */
    b = lcd_rd_data();
    g = r & 0xff;               /* 对于 9341/5310/5510/7789/9806, 第一次读取的是RG的值,R在前,G在后,各占8位 */
    g <<= 8;
    
    return (((r >> 11) << 11) | ((g >> 10) << 5) | (b >> 11));  /* 9341/5310/5510/7789/9806 需要公式转换一下 */
}

/**
  * @brief  画点函数
  * @param  x,y-坐标
  * @param  color-此点的颜色
  * @retval 无
  */
void lcd_draw_point(uint16_t x,uint16_t y,uint32_t color)
{
	lcd_set_cursor(x,y,0,0);
	lcd_write_ram_prepare();
	lcd_write_color(color); 
}

/**
  * @brief  设置LCD显示方向
  * @param  dir- 0)竖屏 1)横屏
  * @retval 无
  */
void lcd_display_dir(uint8_t dir)
{
	if (dir==0) {
		lcddev.dir = 0;
		lcddev.width = 240;
		lcddev.height = 320;
		lcddev.wramcmd = 0x2c;
		lcddev.setxcmd = 0x2a;
		lcddev.setycmd = 0x2b; 
	} else {	  				
		lcddev.dir = 1;
		lcddev.width = 320;
		lcddev.height = 240;
		lcddev.wramcmd = 0x2c;
		lcddev.setxcmd = 0x2a;
		lcddev.setycmd = 0x2b;  	 
	}
}

/**
  * @brief  设置窗口(对RGB屏无效),并自动设置画点坐标到窗口左上角(sx,sy).
  * @param  sx,sy:窗口起始坐标(左上角)
  * @param  width,height:窗口宽度和高度,必须大于0!!
  * @retval 无
  */
void lcd_set_window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height)
{
	uint16_t twidth, theight;
    twidth = sx + width - 1;
    theight = sy + height - 1;
	
	lcd_wr_reg(lcddev.setxcmd);
	lcd_wr_data(sx >> 8);
	lcd_wr_data(sx & 0XFF);
	lcd_wr_data(twidth >> 8);
	lcd_wr_data(twidth & 0XFF);
	lcd_wr_reg(lcddev.setycmd);
	lcd_wr_data(sy >> 8);
	lcd_wr_data(sy & 0XFF);
	lcd_wr_data(theight >> 8);
	lcd_wr_data(theight & 0XFF);
}

/**
  * @brief  清屏函数
  * @param  color-清屏要填充的颜色
  * @retval 无
  */
void lcd_clear(uint16_t color)
{
	uint32_t index=0;      
	uint32_t totalpoint = (lcddev.width + 1);
	totalpoint *= (lcddev.height + 1);		//得到总点数
	lcd_set_cursor(0,0,lcddev.width,lcddev.height);
	lcd_write_ram_prepare();
	
	for(index=0; index<totalpoint; index++) {
		lcd_write_color(color);	
	}
} 

/**
  * @brief  初始化lcd
  * @param  无
  * @retval 无
  */
void lcd_init(void)
{	
	BSP_GpioReset(eLCD_BK);
#ifdef 	USE_XMC_LCD
	gpio_init_type gpio_init_struct;
	xmc_norsram_init_type  xmc_norsram_init_struct;
  	xmc_norsram_timing_init_type  rw_timing_struct, w_timing_struct;
	
	/* enable the gpio clock */
	crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
	/* enable the xmc clock */
	crm_periph_clock_enable(CRM_XMC_PERIPH_CLOCK, TRUE);
	
#if DATA_BIT==16
	gpio_init_struct.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_4 | GPIO_PINS_5 |
								GPIO_PINS_7 | GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10 |
								GPIO_PINS_11 | GPIO_PINS_14 | GPIO_PINS_15;
	gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init(GPIOD, &gpio_init_struct);

	gpio_init_struct.gpio_pins = GPIO_PINS_7 | GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10 | 
								GPIO_PINS_11 | GPIO_PINS_12 | GPIO_PINS_13 | GPIO_PINS_14 |
								GPIO_PINS_15;
	gpio_init(GPIOE, &gpio_init_struct);

	/*-- xmc configuration ------------------------------------------------------*/
	xmc_norsram_default_para_init(&xmc_norsram_init_struct);
	
	xmc_norsram_init_struct.bus_type = XMC_BUSTYPE_16_BITS;
#else
	gpio_init_struct.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_4 | GPIO_PINS_5 |
								GPIO_PINS_7 | GPIO_PINS_11 | GPIO_PINS_14 | GPIO_PINS_15;
	gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init(GPIOD, &gpio_init_struct);

	gpio_init_struct.gpio_pins = GPIO_PINS_7 | GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10;
	gpio_init(GPIOE, &gpio_init_struct);

	/*-- xmc configuration ------------------------------------------------------*/
	xmc_norsram_default_para_init(&xmc_norsram_init_struct);
	
	xmc_norsram_init_struct.bus_type = XMC_BUSTYPE_8_BITS;
#endif
	xmc_norsram_init_struct.subbank = XMC_BANK1_NOR_SRAM1;
	xmc_norsram_init_struct.data_addr_multiplex = XMC_DATA_ADDR_MUX_DISABLE;
	xmc_norsram_init_struct.device = XMC_DEVICE_SRAM;
	xmc_norsram_init_struct.burst_mode_enable = XMC_BURST_MODE_DISABLE;
	xmc_norsram_init_struct.asynwait_enable = XMC_ASYN_WAIT_DISABLE;
	xmc_norsram_init_struct.wait_signal_lv = XMC_WAIT_SIGNAL_LEVEL_LOW;
	xmc_norsram_init_struct.wrapped_mode_enable = XMC_WRAPPED_MODE_DISABLE;
	xmc_norsram_init_struct.wait_signal_config = XMC_WAIT_SIGNAL_SYN_BEFORE;
	xmc_norsram_init_struct.write_enable = XMC_WRITE_OPERATION_ENABLE;
	xmc_norsram_init_struct.wait_signal_enable = XMC_WAIT_SIGNAL_DISABLE;
	xmc_norsram_init_struct.write_timing_enable = XMC_WRITE_TIMING_DISABLE;
	xmc_norsram_init_struct.write_burst_syn = XMC_WRITE_BURST_SYN_DISABLE;
	xmc_nor_sram_init(&xmc_norsram_init_struct);
	
	/* timing configuration */
	xmc_norsram_timing_default_para_init(&rw_timing_struct, &rw_timing_struct);
	
	rw_timing_struct.subbank = XMC_BANK1_NOR_SRAM1;
	rw_timing_struct.write_timing_enable = XMC_WRITE_TIMING_DISABLE;
	rw_timing_struct.addr_hold_time = 0;
	rw_timing_struct.addr_setup_time = 2;
	rw_timing_struct.data_setup_time = 2;
	rw_timing_struct.data_latency_time = 0;
	rw_timing_struct.bus_latency_time = 0;
	rw_timing_struct.clk_psc = 1;
	rw_timing_struct.mode = XMC_ACCESS_MODE_A;
	w_timing_struct.subbank = XMC_BANK1_NOR_SRAM1;
	w_timing_struct.write_timing_enable = XMC_WRITE_TIMING_ENABLE;
	w_timing_struct.addr_setup_time = 2;
	w_timing_struct.addr_hold_time = 0;
	w_timing_struct.data_setup_time = 2;
	w_timing_struct.bus_latency_time = 0;
	w_timing_struct.clk_psc = 0;
	w_timing_struct.data_latency_time = 0;
	w_timing_struct.mode = XMC_ACCESS_MODE_A;

	xmc_nor_sram_timing_config(&rw_timing_struct, &w_timing_struct);
	
	/* bus turnaround phase for consecutive read duration and consecutive write duration */
	xmc_ext_timing_config(XMC_BANK1_NOR_SRAM1, 8, 8);
	
	/* enable xmc_bank1_nor_sram1 */
	xmc_nor_sram_enable(XMC_BANK1_NOR_SRAM1, TRUE);
#endif
	lcd_display_dir(0);

#ifdef 	USE_XMC_LCD
#if DATA_BIT==16
	ili9341_16bit_init();	
	lcd_scan_dir(L2R_U2D);
#else
	gc9307_8bit_init();
	lcd_scan_dir(R2L_U2D);
#endif
#else
	spi4_init();
	gpio_bits_reset(GPIOE, GPIO_PINS_12);
	st7789_spi_init();
	lcd_scan_dir(L2R_U2D);
#endif
	BSP_GpioSet(eLCD_BK);
	Delay_ms(120);
	lcd_display_on();
	lcd_clear(WHITE);
} 

/**
 * @brief       在指定区域内填充单个颜色
 * @param       (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
 * @param       color:  要填充的颜色
 * @retval      无
 */
void lcd_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
{
    uint32_t i;
    uint32_t xlen = 0;
	
#if DATA_BIT==8
    xlen = (ex - sx + 1) * (ey - sy + 1);

	lcd_set_cursor(sx, sy, (ex - sx), (ey - sy));
	lcd_write_ram_prepare();			/* 开始写入GRAM */

	for (i = 0; i < xlen; i++) {
		lcd_write_color(color);			/* 显示颜色 */
	}
#else
	uint16_t j;
	
	xlen = ex - sx + 1;

    for (i = sy; i <= ey; i++) {
        lcd_set_cursor(sx, i, 0, 0);      /* 设置光标位置 */
        lcd_write_ram_prepare();    /* 开始写入GRAM */

        for (j = 0; j < xlen; j++) {
            LCD->LCD_RAM = color;   /* 显示颜色 */
        }
    }
#endif
}

/**
 * @brief       在指定区域内填充指定颜色块
 * @param       (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
 * @param       color: 要填充的颜色数组首地址
 * @retval      无
 */
void lcd_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
{
    uint16_t height, width;
    uint16_t i, j;

    width = ex - sx + 1;            /* 得到填充的宽度 */
    height = ey - sy + 1;           /* 高度 */
#if DATA_BIT==8	
	lcd_set_cursor(sx, sy, ex, ey);	/* 设置光标位置 */
	lcd_write_ram_prepare();		/* 开始写入GRAM */

    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            lcd_write_color(color[i * width + j]); /* 写入数据 */
        }
    }
#else
	for (i = 0; i < height; i++) {
        lcd_set_cursor(sx, sy + i, 0, 0); /* 设置光标位置 */
        lcd_write_ram_prepare();    /* 开始写入GRAM */

        for (j = 0; j < width; j++) {
            LCD->LCD_RAM = color[i * width + j]; /* 写入数据 */
        }
    }
#endif
}

/**
 * @brief       画线
 * @param       x1,y1: 起点坐标
 * @param       x2,y2: 终点坐标
 * @param       color: 线的颜色
 * @retval      无
 */
void lcd_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    uint16_t t;
    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
    int incx, incy, row, col;
    delta_x = x2 - x1;      /* 计算坐标增量 */
    delta_y = y2 - y1;
    row = x1;
    col = y1;

    if (delta_x > 0) {
        incx = 1;       /* 设置单步方向 */
    } else if (delta_x == 0) {
        incx = 0;       /* 垂直线 */
    } else {
        incx = -1;
        delta_x = -delta_x;
    }

    if (delta_y > 0) {
        incy = 1;
    } else if (delta_y == 0) {
        incy = 0;       /* 水平线 */
    } else {
        incy = -1;
        delta_y = -delta_y;
    }

    if ( delta_x > delta_y) {
        distance = delta_x;  /* 选取基本增量坐标轴 */
    } else {
        distance = delta_y;
    }

    for (t = 0; t <= distance + 1; t++) {	/* 画线输出 */
    
        lcd_draw_point(row, col, color);		/* 画点 */
        xerr += delta_x;
        yerr += delta_y;

        if (xerr > distance) {
            xerr -= distance;
            row += incx;
        }

        if (yerr > distance) {
            yerr -= distance;
            col += incy;
        }
    }
}

/**
 * @brief       画水平线
 * @param       x,y   : 起点坐标
 * @param       len   : 线长度
 * @param       color : 矩形的颜色
 * @retval      无
 */
void lcd_draw_hline(uint16_t x, uint16_t y, uint16_t len, uint16_t color)
{
    if ((len == 0) || (x > lcddev.width) || (y > lcddev.height)) {
        return;
    }

    lcd_fill(x, y, x + len - 1, y, color);
}

/**
 * @brief       画矩形
 * @param       x1,y1: 起点坐标
 * @param       x2,y2: 终点坐标
 * @param       color: 矩形的颜色
 * @retval      无
 */
void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    lcd_draw_line(x1, y1, x2, y1, color);
    lcd_draw_line(x1, y1, x1, y2, color);
    lcd_draw_line(x1, y2, x2, y2, color);
    lcd_draw_line(x2, y1, x2, y2, color);
}

/**
 * @brief       画圆
 * @param       x0,y0 : 圆中心坐标
 * @param       r     : 半径
 * @param       color : 圆的颜色
 * @retval      无
 */
void lcd_draw_circle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
{
    int a, b;
    int di;

    a = 0;
    b = r;
    di = 3 - (r << 1);       /* 判断下个点位置的标志 */

    while (a <= b) {
        lcd_draw_point(x0 + a, y0 - b, color);  /* 5 */
        lcd_draw_point(x0 + b, y0 - a, color);  /* 0 */
        lcd_draw_point(x0 + b, y0 + a, color);  /* 4 */
        lcd_draw_point(x0 + a, y0 + b, color);  /* 6 */
        lcd_draw_point(x0 - a, y0 + b, color);  /* 1 */
        lcd_draw_point(x0 - b, y0 + a, color);
        lcd_draw_point(x0 - a, y0 - b, color);  /* 2 */
        lcd_draw_point(x0 - b, y0 - a, color);  /* 7 */
        a++;

        /* 使用Bresenham算法画圆 */
        if (di < 0) {
            di += 4 * a + 6;
        } else {
            di += 10 + 4 * (a - b);
            b--;
        }
    }
}

/**
 * @brief       填充实心圆
 * @param       x,y  : 圆中心坐标
 * @param       r    : 半径
 * @param       color: 圆的颜色
 * @retval      无
 */
void lcd_fill_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color)
{
    uint32_t i;
    uint32_t imax = ((uint32_t)r * 707) / 1000 + 1;
    uint32_t sqmax = (uint32_t)r * (uint32_t)r + (uint32_t)r / 2;
    uint32_t xr = r;

    lcd_draw_hline(x - r, y, 2 * r, color);

    for (i = 1; i <= imax; i++) {
        if ((i * i + xr * xr) > sqmax) {
            /* draw lines from outside */
            if (xr > imax) {
                lcd_draw_hline (x - i + 1, y + xr, 2 * (i - 1), color);
                lcd_draw_hline (x - i + 1, y - xr, 2 * (i - 1), color);
            }
            xr--;
        }

        /* draw lines from inside (center) */
        lcd_draw_hline(x - xr, y + i, 2 * xr, color);
        lcd_draw_hline(x - xr, y - i, 2 * xr, color);
    }
}

/**
 * @brief       在指定位置显示一个字符
 * @param       x,y  : 坐标
 * @param       chr  : 要显示的字符:" "--->"~"
 * @param       size : 字体大小 12/16/24/32
 * @param       mode : 叠加方式(1); 非叠加方式(0);
 * @param       color : 字符的颜色;
 * @retval      无
 */
void lcd_show_char(uint16_t x, uint16_t y, char chr, uint8_t size, uint8_t mode, uint16_t color)
{
    uint8_t temp, t1, t;
    uint16_t y0 = y;
    uint8_t csize = 0;
    uint8_t *pfont = 0;

    csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2); /* 得到字体一个字符对应点阵集所占的字节数 */
    chr = chr - ' ';    /* 得到偏移后的值（ASCII字库是从空格开始取模，所以-' '就是对应字符的字库） */

    switch (size) {
        case 12:
            pfont = (uint8_t *)asc2_1206[chr];  /* 调用1206字体 */
            break;

        case 16:
            pfont = (uint8_t *)asc2_1608[chr];  /* 调用1608字体 */
            break;

        case 24:
            pfont = (uint8_t *)asc2_2412[chr];  /* 调用2412字体 */
            break;

        case 32:
            pfont = (uint8_t *)asc2_3216[chr];  /* 调用3216字体 */
            break;

        default:
            return ;
    }

    for (t = 0; t < csize; t++) {
        temp = pfont[t];                            /* 获取字符的点阵数据 */
        for (t1 = 0; t1 < 8; t1++) {				/* 一个字节8个点 */        
            if (temp & 0x80) {						/* 有效点,需要显示 */           
                lcd_draw_point(x, y, color);		/* 画点出来,要显示这个点 */
            } else if (mode == 0) {                 /* 无效点,不显示 */    
                lcd_draw_point(x, y, g_back_color); 		/* 画背景色,相当于这个点不显示(注意背景色由全局变量控制) */
            }

            temp <<= 1;                             /* 移位, 以便获取下一个位的状态 */
            y++;

            if (y >= lcddev.height) return;			/* 超区域了 */

            if ((y - y0) == size) {					/* 显示完一列了? */         
                y = y0; /* y坐标复位 */
                x++;    /* x坐标递增 */
                if (x >= lcddev.width) {
                    return;       /* x坐标超区域了 */
                }

                break;
            }
        }
    }
}

/**
 * @brief       平方函数, m^n
 * @param       m: 底数
 * @param       n: 指数
 * @retval      m的n次方
 */
static uint32_t lcd_pow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;

    while (n--) {
        result *= m;
    }

    return result;
}

/**
 * @brief       显示len个数字
 * @param       x,y : 起始坐标
 * @param       num : 数值(0 ~ 2^32)
 * @param       len : 显示数字的位数
 * @param       size: 选择字体 12/16/24/32
 * @param       color : 数字的颜色;
 * @retval      无
 */
void lcd_show_num(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint16_t color)
{
    uint8_t t, temp;
    uint8_t enshow = 0;

    for (t = 0; t < len; t++) {							/* 按总显示位数循环 */ 
        temp = (num / lcd_pow(10, len - t - 1)) % 10;   /* 获取对应位的数字 */
        if (enshow == 0 && t < (len - 1)) {             /* 没有使能显示,且还有位要显示 */     
            if (temp == 0) {          
                lcd_show_char(x + (size / 2) * t, y, ' ', size, 0, color);  /* 显示空格,占位 */
                continue;       /* 继续下个一位 */
            } else {
                enshow = 1;     /* 使能显示 */
            }
        }

        lcd_show_char(x + (size / 2) * t, y, temp + '0', size, 0, color);   /* 显示字符 */
    }
}

/**
 * @brief       扩展显示len个数字(高位是0也显示)
 * @param       x,y : 起始坐标
 * @param       num : 数值(0 ~ 2^32)
 * @param       len : 显示数字的位数
 * @param       size: 选择字体 12/16/24/32
 * @param       mode: 显示模式
 *              [7]:0,不填充;1,填充0.
 *              [6:1]:保留
 *              [0]:0,非叠加显示;1,叠加显示.
 * @param       color : 数字的颜色;
 * @retval      无
 */
void lcd_show_xnum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode, uint16_t color)
{
    uint8_t t, temp;
    uint8_t enshow = 0;

    for (t = 0; t < len; t++) {      					/* 按总显示位数循环 */  
        temp = (num / lcd_pow(10, len - t - 1)) % 10;	/* 获取对应位的数字 */
        if (enshow == 0 && t < (len - 1)) {				/* 没有使能显示,且还有位要显示 */     
            if (temp == 0) {
                if (mode & 0x80) {						/* 高位需要填充0 */               
                    lcd_show_char(x + (size / 2) * t, y, '0', size, mode & 0x01, color);    /* 用0占位 */
                } else {
                    lcd_show_char(x + (size / 2) * t, y, ' ', size, mode & 0x01, color);    /* 用空格占位 */
                }

                continue;
            } else {
                enshow = 1;								/* 使能显示 */
            }
        }

        lcd_show_char(x + (size / 2) * t, y, temp + '0', size, mode & 0x01, color);
    }
}

/**
 * @brief       显示字符串
 * @param       x,y         : 起始坐标
 * @param       width,height: 区域大小
 * @param       size        : 选择字体 12/16/24/32
 * @param       p           : 字符串首地址
 * @param       color       : 字符串的颜色;
 * @retval      无
 */
void lcd_show_string(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, char *p, uint16_t color)
{
    uint8_t x0 = x;
    
    width += x;
    height += y;

    while ((*p <= '~') && (*p >= ' ')) {	/* 判断是不是非法字符! */
        if (x >= width) {
            x = x0;
            y += size;
        }

        if (y >= height) {
            break;      /* 退出 */
        }

        lcd_show_char(x, y, *p, size, 0, color);
        x += size / 2;
        p++;
    }
}

/**
  * @brief  从8位数据获得16位颜色
  * @param  mode-0,低位在前,高位在后;1,高位在前,低位在后.
  * @param  str-数据
  * @retval 16位颜色
  */
uint16_t image_getcolor(uint8_t mode,uint8_t *str)
{
	uint16_t color;

	if(mode) {
		color = ((uint16_t)*str++) << 8;
		color |= *str;
	} else {
		color = *str++;
		color |= ((uint16_t)*str) << 8;
	}

	return color;
}

/**
  * @brief  在LCD上显示图片
  * @param  xsta,ysta,xend,yend-图片显示区域
  * @param  *p-图像数据
  * @retval 无
  */
void image_show(uint8_t *p, uint16_t xsta, uint16_t ysta, uint16_t width, uint16_t height)
{ 
	uint32_t i;
	uint32_t len=0;

	lcd_set_window(xsta, ysta, width, height);

	lcd_write_ram_prepare();
	len = width * height;  //写入的数据长度

	for(i=0; i<len; i++) {
		lcd_write_color(image_getcolor(0,p));
		p += 2;
	}
}

/* FILE END */
